package com.gem.day15;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Ticket {
	public static void main(String[] args) {
		Runnable r = new TicketThread();
		Thread t1 = new Thread(r, "窗口1");
		Thread t2 = new Thread(r, "窗口2");
		Thread t3 = new Thread(r, "窗口3");
		t1.start();
		t2.start();
		t3.start();
	}
}

class TicketThread implements Runnable {
	//成员变量,多个线程同时操作
	private int ticket = 100;

	//创建Lock对象
	Lock lock = new ReentrantLock();

	/*
	 *	同步代码块和同步方法加锁的异同
	 *
	 * 相同点:都可以实现线程同步安全,性能会降低,安全提升.
	 * 
	 * 不同点:
	 * 同步方法加锁的级别是方法,所以加锁范围大,性能损耗较大
	 * 同步代码块加锁范围是局部代码片段,所以加锁范围小,性能损耗较小
	 * 
	 * 同步方法加锁只是方法级别的,即一锁一方法
	 * 同步代码块加锁是代码片段级别的,所以可以同时制定多个锁标记
	 * 
	 * 注意:
	 * 如果同步代码使用synchronized (this),则相当于同步方法!
	 * 
	 * Lock锁方式:
	 * 以面向对象的方式加锁和解锁,更加灵活
	 * 
	 */
	@Override
	public void run() {
		while (true) {
			//同步代码块
			/*synchronized (this) {
				if (ticket > 0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					String name = Thread.currentThread().getName();
					System.out.println(name + "正在卖: " + ticket--);
				}
			}*/

			sell();
		}
	}

	//同步方法
	/*public synchronized void sell() {
		if (ticket > 0) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			String name = Thread.currentThread().getName();
			System.out.println(name + "正在卖: " + ticket--);
		}
	}*/

	public void sell() {
		//加锁
		lock.lock();
		if (ticket > 0) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			String name = Thread.currentThread().getName();
			System.out.println(name + "正在卖: " + ticket--);
		}
		//解锁
		lock.unlock();
	}
}
